package edu.uc.labs.MobilePrinting.OSUtils;

import edu.uc.labs.MobilePrinting.Configurator;

import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import org.apache.log4j.Logger;

/**
 * 
 * @author Matthew Silbernagel This Class sets up the Mobile Print Service and
 *         provides the method for running the service
 * 
 */
public class IPAddressFinder {

	private String ip = null;
	final private String IP = "127.0.0.1";
	private Logger logger = Configurator.LOGGER;

	/**
	 * Constructor for IPAddressFinder
	 */
	public IPAddressFinder() throws UnknownHostException {
		// Get an local IP Address
		// and get the hostname based on that
		ip = "127.0.0.1";
	}

	/*
	 * Method that returns a string representation of the localhost's IP Address
	 * 
	 * @return string ipaddress
	 */
	public String getIP() {
		try {
			Enumeration<NetworkInterface> e = NetworkInterface
					.getNetworkInterfaces();
			while (e.hasMoreElements()) {
				NetworkInterface ni = (NetworkInterface) e.nextElement();
				Enumeration<InetAddress> e2 = ni.getInetAddresses();
				while (e2.hasMoreElements()) {
					InetAddress inet = (InetAddress) e2.nextElement();
					String stringIP = cleanup(inet.toString(), "/", false);

					// Check if we have a 'UC' Address
					if (stringIP.matches("^10\\.\\d+\\.\\d+\\.\\d+")) {
						// We seem to have a UC formed IP Address, can we
						// reach the configuration server?
						if (canPingServer()) {
							return stringIP;
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("Can not get IP Address " + e.toString()
					+ " returning the default value");
			return IP;
		}

		try {
			Enumeration<NetworkInterface> e = NetworkInterface
					.getNetworkInterfaces();
			while (e.hasMoreElements()) {
				NetworkInterface ni = (NetworkInterface) e.nextElement();
				Enumeration<InetAddress> e2 = ni.getInetAddresses();
				while (e2.hasMoreElements()) {
					InetAddress inet = (InetAddress) e2.nextElement();
					String stringIP = cleanup(inet.toString(), "/", false);

					// Check if we have a 'UC' Address
					if (stringIP.matches("^172\\.\\d+\\.\\d+\\.\\d+")) {
						// We seem to have a UC formed IP Address, can we
						// reach the configuration server?
						if (canPingServer()) {
							return stringIP;
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("Can not get IP Address " + e.toString()
					+ " returning the default value");
			return IP;
		}

		return ip;

	}

	/**
	 * Setter for the IP Address
	 * 
	 * @param addr
	 *            The address to set
	 */
	public boolean setIP(String addr) {
		this.ip = addr;
		if (this.ip.equals(addr)) {
			return true;
		}
		return false;
	}

	/**
	 * Method that compares two IP Addresses
	 */
	public boolean isEqual(String otherIP) {
		if (ip.equals(otherIP)) {
			return true;
		}
		return false;
	}

	/**
	 * Method that determines if the IP passed in is the same as the current
	 * object holds
	 * 
	 * @param myNewIP
	 *            the ip to compare against
	 * @return true if the IP's are different
	 */
	public boolean hasChanged(String myNewIP) {
		if (this.ip.equals(myNewIP)) {
			logger.debug("Your IP has not changed ");
			// if the two addresses are equal
			// then there is nothing to do
			return false;
		} else {
			logger.debug("Your IP has changed");
			// otherwise there is a change
			// in the IP address
			// set the new IP Address
			this.ip = myNewIP;
			return true;
		}
	}

	/**
	 * @return a string representation of the current IP address
	 */
	public String toString() {
		return ip;
	}

	/**
	 * Determines if the configuration server is reachable. Very similar to
	 * pinging. The configuration server is determined by
	 * Configurator.HTTP_SERVER
	 * 
	 * @return true if the server is reachable
	 */
	private boolean canPingServer() {

		try {
			InetAddress configServer = InetAddress
					.getByName(Configurator.HTTP_SERVER);
			if (configServer.isReachable(3000)) {
				return true;
			}
		} catch (UnknownHostException e2) {
			logger.error("Unkown Host " + Configurator.HTTP_SERVER);
			return false;
		} catch (IOException e1) {
			// We can't reach the server
			logger.error("The configuration server is unreachable...");
			return false;
		}
		return false;
	}

	/**
	 * Clean characters from a string
	 * 
	 * @param s
	 *            String to clean
	 * @param sToMatch
	 *            character to clean
	 * @param isToKeep
	 * @return
	 */
	private String cleanup(String s, String sToMatch, boolean isToKeep) {
		final int size = s.length();
		StringBuffer buf = new StringBuffer(size);
		if (!isToKeep) {
			for (int i = 0; i < size; i++) {
				if (sToMatch.indexOf(s.charAt(i)) == -1) {
					buf.append(s.charAt(i));
				}
			}
		} else {
			for (int i = 0; i < size; i++) {
				if (sToMatch.indexOf(s.charAt(i)) != -1) {
					buf.append(s.charAt(i));
				}
			}
		}
		return buf.toString();

	}

}
